Load libraries

library(Seurat)
library(Matrix)
library(dplyr)
library(RColorBrewer)
library(ggplot2)
library(ggExtra)
library(cowplot)
library(reticulate)
library(wesanderson)
use_python("/usr/bin/python3")

#Set ggplot theme as classic
theme_set(theme_classic())

Load the raw counts matrix

Countdata <- Read10X("../../RawData/Gmnc_KO/outs/filtered_feature_bc_matrix/")

Raw.data <- CreateSeuratObject(counts = Countdata,
                              project = "Gmnc_KO",
                              min.cells = 3,
                              min.features = 800)

Raw.data$Barcodes <- rownames(Raw.data@meta.data)

rm(Countdata)

dim(Raw.data)
## [1] 21077 16272
Raw.data$percent.mito <- PercentageFeatureSet(Raw.data, pattern = "^mt-")
Raw.data$percent.ribo <- PercentageFeatureSet(Raw.data, pattern = "(^Rpl|^Rps|^Mrp)")
VlnPlot(object = Raw.data, features = c("nFeature_RNA","nCount_RNA", "percent.mito", "percent.ribo"), ncol= 2) & NoAxes()

# Inspect cell based on relation between nUMI and nGene detected

# Relation between nUMI and nGene detected
Cell.QC.Stat <- Raw.data@meta.data

p1 <- ggplot(Cell.QC.Stat, aes(x=nCount_RNA, y=nFeature_RNA)) + geom_point() + geom_smooth(method="lm")
p1 <- ggMarginal(p1, type = "histogram", fill="lightgrey")

p2 <- ggplot(Cell.QC.Stat, aes(x=log10(nCount_RNA), y=log10(nFeature_RNA))) + geom_point() + geom_smooth(method="lm")
p2 <- ggMarginal(p2, type = "histogram", fill="lightgrey")

plot_grid(plotlist = list(p1,p2), ncol=2, align='h', rel_widths = c(1, 1)) ; rm(p1,p2)

Cells with deviating nGene/nUMI ratio display an Erythrocyte signature

Raw.data <- AddModuleScore(Raw.data,
                           features = list(c("Hbb-bt", "Hbq1a", "Isg20", "Fech", "Snca", "Rec114")),
                           ctrl = 10,
                           name = "Erythrocyte.signature")

Cell.QC.Stat$Erythrocyte.signature <- Raw.data$Erythrocyte.signature1
gradient <- colorRampPalette(brewer.pal(n =11, name = "Spectral"))(100)

p1 <- ggplot(Cell.QC.Stat, aes(log10(nCount_RNA), y=log10(nFeature_RNA))) +
      geom_point(aes(color= Erythrocyte.signature))  + 
      scale_color_gradientn(colours=rev(gradient), name='Erythrocyte score') + theme(legend.position="none")

p2 <- ggplot(Cell.QC.Stat, aes(log10(nCount_RNA), y=log10(nFeature_RNA))) +
      geom_point(aes(color= percent.mito))  + 
      scale_color_gradientn(colours=rev(gradient), name='Percent mito') + theme(legend.position="none")

p3 <- ggplot(Cell.QC.Stat, aes(log10(nCount_RNA), y=log10(nFeature_RNA))) +
      geom_point(aes(color= percent.ribo))  + 
      scale_color_gradientn(colours=rev(gradient), name='Percent ribo') + theme(legend.position="none")

p1 + p2 + p3

## Exclude Erythrocytes

Cell.QC.Stat$Erythrocyte <- ifelse(Cell.QC.Stat$Erythrocyte.signature > 0.1, "Erythrocyte", "Not_Erythrocyte")
p2 <- ggplot(Cell.QC.Stat, aes(x=log10(nCount_RNA), y=log10(nFeature_RNA))) +
  geom_point(aes(colour = Erythrocyte)) +
  theme(legend.position="none")

ggMarginal(p2, type = "histogram", fill="lightgrey")

# Filter cells based on these thresholds
Cell.QC.Stat <- Cell.QC.Stat %>% filter(Cell.QC.Stat$Erythrocyte.signature < 0.1)

Low quality cell filtering

Filtering cells based on percentage of mitochondrial transcripts

We applied a high and low median absolute deviation (mad) thresholds to exclude outlier cells

max.mito.thr <- median(Cell.QC.Stat$percent.mito) + 3*mad(Cell.QC.Stat$percent.mito)
min.mito.thr <- median(Cell.QC.Stat$percent.mito) - 3*mad(Cell.QC.Stat$percent.mito)
p1 <- ggplot(Cell.QC.Stat, aes(x=nFeature_RNA, y=percent.mito)) +
  geom_point() +
  geom_hline(aes(yintercept = max.mito.thr), colour = "red", linetype = 2) +
  geom_hline(aes(yintercept = min.mito.thr), colour = "red", linetype = 2) +
  annotate(geom = "text", label = paste0(as.numeric(table(Cell.QC.Stat$percent.mito > max.mito.thr | Cell.QC.Stat$percent.mito < min.mito.thr)[2])," cells removed\n",
                                         as.numeric(table(Cell.QC.Stat$percent.mito > max.mito.thr | Cell.QC.Stat$percent.mito < min.mito.thr)[1])," cells remain"),
           x = 6000, y = 20)

ggMarginal(p1, type = "histogram", fill="lightgrey", bins=100) 

# Filter cells based on these thresholds
Cell.QC.Stat <- Cell.QC.Stat %>% filter(percent.mito < max.mito.thr) %>% filter(percent.mito > min.mito.thr)

Filtering cells based on number of genes and transcripts detected

Remove cells with to few gene detected or with to many UMI counts

We filter cells which are likely to be doublet based on their higher content of transcript detected as well as cell with to few genes/UMI sequenced

# Set low and hight thresholds on the number of detected genes based on the one obtain with the WT dataset
min.Genes.thr <- log10(1635)
max.Genes.thr <- log10(8069)

# Set hight threshold on the number of transcripts
max.nUMI.thr <- log10(58958)
# Gene/UMI scatter plot before filtering
p1 <- ggplot(Cell.QC.Stat, aes(x=log10(nCount_RNA), y=log10(nFeature_RNA))) +
  geom_point() +
  geom_smooth(method="lm") +
  geom_hline(aes(yintercept = min.Genes.thr), colour = "green", linetype = 2) +
  geom_hline(aes(yintercept = max.Genes.thr), colour = "green", linetype = 2) +
  geom_vline(aes(xintercept = max.nUMI.thr), colour = "red", linetype = 2)

ggMarginal(p1, type = "histogram", fill="lightgrey")

# Filter cells base on both metrics
Cell.QC.Stat <- Cell.QC.Stat %>% filter(log10(nFeature_RNA) > min.Genes.thr) %>% filter(log10(nCount_RNA) < max.nUMI.thr)

Filter cells below the main population nUMI/nGene relationship

lm.model <- lm(data = Cell.QC.Stat, formula = log10(nFeature_RNA) ~ log10(nCount_RNA))

p2 <- ggplot(Cell.QC.Stat, aes(x=log10(nCount_RNA), y=log10(nFeature_RNA))) +
  geom_point() +
  geom_smooth(method="lm") +
  geom_hline(aes(yintercept = min.Genes.thr), colour = "green", linetype = 2) +
  geom_hline(aes(yintercept = max.Genes.thr), colour = "green", linetype = 2) +
  geom_vline(aes(xintercept = max.nUMI.thr), colour = "red", linetype = 2) +
  annotate(geom = "text", label = paste0(dim(Cell.QC.Stat)[1], " QC passed cells"), x = 4, y = 3.8)

ggMarginal(p2, type = "histogram", fill="lightgrey")

## Filter the Seurat object

Raw.data <- subset(x = Raw.data, subset = Barcodes %in%  Cell.QC.Stat$Barcodes)
# Plot final QC metrics
VlnPlot(object = Raw.data, features = c("nFeature_RNA","nCount_RNA", "percent.mito", "percent.ribo"), ncol= 2) & NoAxes()

p1 <- ggplot(Raw.data@meta.data, aes(x=log10(nCount_RNA), y=log10(nFeature_RNA))) + geom_point() + geom_smooth(method="lm")
ggMarginal(p1, type = "histogram", fill="lightgrey")

rm(list = ls()[!ls() %in% "Raw.data"])

Use Scrublet to detect obvious doublets

Run Scrublet with default parameter

Export raw count matrix as input to Scrublet

#Export filtered matrix
dir.create("../../RawData/Gmnc_KO/Scrublet_inputs")

exprData <- Matrix(as.matrix(Raw.data@assays[["RNA"]]@counts), sparse = TRUE)
writeMM(exprData, "../../RawData/Gmnc_KO/Scrublet_inputs/matrix1.mtx")
## NULL
import scrublet as scr
import scipy.io
import numpy as np
import os

#Load raw counts matrix and gene list
input_dir = '../../RawData/Gmnc_KO/Scrublet_inputs'
counts_matrix = scipy.io.mmread(input_dir + '/matrix1.mtx').T.tocsc()

#Initialize Scrublet
scrub = scr.Scrublet(counts_matrix,
                     expected_doublet_rate=0.1,
                     sim_doublet_ratio=2,
                     n_neighbors = 8)

#Run the default pipeline
doublet_scores, predicted_doublets = scrub.scrub_doublets(min_counts=1, 
                                                          min_cells=3, 
                                                          min_gene_variability_pctl=85, 
                                                          n_prin_comps=25)
## Preprocessing...
## Simulating doublets...
## Embedding transcriptomes using PCA...
## Calculating doublet scores...
## Automatically set threshold at doublet score = 0.35
## Detected doublet rate = 3.7%
## Estimated detectable doublet fraction = 26.0%
## Overall doublet rate:
##  Expected   = 10.0%
##  Estimated  = 14.2%
## Elapsed time: 19.7 seconds
# Import scrublet's doublet score
Raw.data$Doubletscore <- py$doublet_scores

# Plot doublet score
ggplot(Raw.data@meta.data, aes(x = Doubletscore, stat(ndensity))) +
  geom_histogram(bins = 200, colour ="lightgrey")+
  geom_vline(xintercept = 0.15, colour = "red", linetype = 2)

# Manually set threshold at doublet score to 0.2
Raw.data$Predicted_doublets <- ifelse(py$doublet_scores > 0.15, "Doublet","Singlet")
table(Raw.data$Predicted_doublets)
## 
## Doublet Singlet 
##    2273   10215
Raw.data <- subset(x = Raw.data, subset = Predicted_doublets == "Singlet")

Generate SRING dimentionality reduction

Export counts matrix

dir.create("./SpringCoordinates")
# Export raw expression matrix and gene list to regenerate a spring plot
exprData <- Matrix(as.matrix(Raw.data@assays[["RNA"]]@counts), sparse = TRUE)
writeMM(exprData, "./SpringCoordinates/ExprData.mtx")
## NULL
Genelist <- row.names(Raw.data@assays[["RNA"]]@counts)
write.table(Genelist, "./SpringCoordinates/Genelist.csv", sep="\t", col.names = F, row.names = F, quote = F)
#Export metadata
Scrublet <- c("Scrublet", Raw.data$Predicted_doublets)
Scrublet <- paste(Scrublet, sep=",", collapse=",")

Cellgrouping <- Scrublet
write.table(Cellgrouping, "./SpringCoordinates/Cellgrouping.csv", quote =F, row.names = F, col.names = F)

Import coordinates

spring.coor <- read.table("SpringCoordinates/coordinates.txt", sep = ",", header = F, row.names = 1)
colnames(spring.coor) <- c("Spring_1", "Spring_2")
Spring.Sym <- function(x){
  x = abs(max(spring.coor$Spring_2)-x)
 }

spring.coor$Spring_2 <- sapply(spring.coor$Spring_2, function(x) Spring.Sym(x))
Raw.data$Spring_1 <- spring.coor$Spring_1
Raw.data$Spring_2 <- spring.coor$Spring_2
spring <- as.matrix(Raw.data@meta.data %>% select("Spring_1", "Spring_2"))
  
Raw.data[["spring"]] <- CreateDimReducObject(embeddings = spring, key = "Spring_", assay = DefaultAssay(Raw.data))
DimPlot(Raw.data, 
        reduction = "spring",
        pt.size = 0.5) & NoAxes()

# Sctransform normalization

Raw.data <- SCTransform(Raw.data,
                        method = "glmGamPoi",
                        vars.to.regress = c("percent.mito"),
                        verbose = T)
## 
  |                                                                            
  |                                                                      |   0%
  |                                                                            
  |==================                                                    |  25%
  |                                                                            
  |===================================                                   |  50%
  |                                                                            
  |====================================================                  |  75%
  |                                                                            
  |======================================================================| 100%
## 
  |                                                                            
  |                                                                      |   0%
  |                                                                            
  |==                                                                    |   3%
  |                                                                            
  |====                                                                  |   5%
  |                                                                            
  |=====                                                                 |   8%
  |                                                                            
  |=======                                                               |  10%
  |                                                                            
  |=========                                                             |  13%
  |                                                                            
  |===========                                                           |  15%
  |                                                                            
  |=============                                                         |  18%
  |                                                                            
  |==============                                                        |  21%
  |                                                                            
  |================                                                      |  23%
  |                                                                            
  |==================                                                    |  26%
  |                                                                            
  |====================                                                  |  28%
  |                                                                            
  |======================                                                |  31%
  |                                                                            
  |=======================                                               |  33%
  |                                                                            
  |=========================                                             |  36%
  |                                                                            
  |===========================                                           |  38%
  |                                                                            
  |=============================                                         |  41%
  |                                                                            
  |===============================                                       |  44%
  |                                                                            
  |================================                                      |  46%
  |                                                                            
  |==================================                                    |  49%
  |                                                                            
  |====================================                                  |  51%
  |                                                                            
  |======================================                                |  54%
  |                                                                            
  |=======================================                               |  56%
  |                                                                            
  |=========================================                             |  59%
  |                                                                            
  |===========================================                           |  62%
  |                                                                            
  |=============================================                         |  64%
  |                                                                            
  |===============================================                       |  67%
  |                                                                            
  |================================================                      |  69%
  |                                                                            
  |==================================================                    |  72%
  |                                                                            
  |====================================================                  |  74%
  |                                                                            
  |======================================================                |  77%
  |                                                                            
  |========================================================              |  79%
  |                                                                            
  |=========================================================             |  82%
  |                                                                            
  |===========================================================           |  85%
  |                                                                            
  |=============================================================         |  87%
  |                                                                            
  |===============================================================       |  90%
  |                                                                            
  |=================================================================     |  92%
  |                                                                            
  |==================================================================    |  95%
  |                                                                            
  |====================================================================  |  97%
  |                                                                            
  |======================================================================| 100%
## 
  |                                                                            
  |                                                                      |   0%
  |                                                                            
  |==                                                                    |   3%
  |                                                                            
  |====                                                                  |   5%
  |                                                                            
  |=====                                                                 |   8%
  |                                                                            
  |=======                                                               |  10%
  |                                                                            
  |=========                                                             |  13%
  |                                                                            
  |===========                                                           |  15%
  |                                                                            
  |=============                                                         |  18%
  |                                                                            
  |==============                                                        |  21%
  |                                                                            
  |================                                                      |  23%
  |                                                                            
  |==================                                                    |  26%
  |                                                                            
  |====================                                                  |  28%
  |                                                                            
  |======================                                                |  31%
  |                                                                            
  |=======================                                               |  33%
  |                                                                            
  |=========================                                             |  36%
  |                                                                            
  |===========================                                           |  38%
  |                                                                            
  |=============================                                         |  41%
  |                                                                            
  |===============================                                       |  44%
  |                                                                            
  |================================                                      |  46%
  |                                                                            
  |==================================                                    |  49%
  |                                                                            
  |====================================                                  |  51%
  |                                                                            
  |======================================                                |  54%
  |                                                                            
  |=======================================                               |  56%
  |                                                                            
  |=========================================                             |  59%
  |                                                                            
  |===========================================                           |  62%
  |                                                                            
  |=============================================                         |  64%
  |                                                                            
  |===============================================                       |  67%
  |                                                                            
  |================================================                      |  69%
  |                                                                            
  |==================================================                    |  72%
  |                                                                            
  |====================================================                  |  74%
  |                                                                            
  |======================================================                |  77%
  |                                                                            
  |========================================================              |  79%
  |                                                                            
  |=========================================================             |  82%
  |                                                                            
  |===========================================================           |  85%
  |                                                                            
  |=============================================================         |  87%
  |                                                                            
  |===============================================================       |  90%
  |                                                                            
  |=================================================================     |  92%
  |                                                                            
  |==================================================================    |  95%
  |                                                                            
  |====================================================================  |  97%
  |                                                                            
  |======================================================================| 100%

Run PCA and broad clustering

Raw.data <- RunPCA(Raw.data, verbose = FALSE)

Raw.data <- FindNeighbors(Raw.data,
                          dims = 1:20,
                          k.param = 8)

Raw.data <- FindClusters(Raw.data, resolution = 0.1)
## Modularity Optimizer version 1.3.0 by Ludo Waltman and Nees Jan van Eck
## 
## Number of nodes: 10215
## Number of edges: 218490
## 
## Running Louvain algorithm...
## Maximum modularity in 10 random starts: 0.9542
## Number of communities: 7
## Elapsed time: 1 seconds
DimPlot(Raw.data,
        reduction = "spring",
        cols = c(wes_palette("FantasticFox1"),"#9ec22f","grey60"),
        pt.size = 0.5) & NoAxes()

Plot marker genes found in the WT dataset

FeaturePlot(object = Raw.data,
            features = c("Tbr1","Foxg1", "Trp73", "Htr2c",
                         "Shisa2", "Wif1", "Rassf4","Dkk3",
                         "Dlk1", "Sulf1", "Ttr", "Foxc1", "C1qb"),
            pt.size = 0.2,
            cols = c("grey90", brewer.pal(9,"YlGnBu")),
            reduction = "spring",
            order = T) & NoAxes() & NoLegend()

Save the object

saveRDS(Raw.data, "./GmncKO.cells.RDS")

Session Info

#date
format(Sys.time(), "%d %B, %Y, %H,%M")
## [1] "22 avril, 2022, 10,39"
#Packages used
sessionInfo()
## R version 4.1.3 (2022-03-10)
## Platform: x86_64-pc-linux-gnu (64-bit)
## Running under: Ubuntu 20.04.4 LTS
## 
## Matrix products: default
## BLAS:   /usr/lib/x86_64-linux-gnu/blas/libblas.so.3.9.0
## LAPACK: /home/matthieu/anaconda3/lib/libmkl_rt.so.1
## 
## locale:
##  [1] LC_CTYPE=fr_FR.UTF-8       LC_NUMERIC=C              
##  [3] LC_TIME=fr_FR.UTF-8        LC_COLLATE=fr_FR.UTF-8    
##  [5] LC_MONETARY=fr_FR.UTF-8    LC_MESSAGES=fr_FR.UTF-8   
##  [7] LC_PAPER=fr_FR.UTF-8       LC_NAME=C                 
##  [9] LC_ADDRESS=C               LC_TELEPHONE=C            
## [11] LC_MEASUREMENT=fr_FR.UTF-8 LC_IDENTIFICATION=C       
## 
## attached base packages:
## [1] stats     graphics  grDevices utils     datasets  methods   base     
## 
## other attached packages:
##  [1] wesanderson_0.3.6  reticulate_1.22    cowplot_1.1.1      ggExtra_0.9       
##  [5] ggplot2_3.3.5      RColorBrewer_1.1-2 dplyr_1.0.7        Matrix_1.4-1      
##  [9] SeuratObject_4.0.4 Seurat_4.0.5      
## 
## loaded via a namespace (and not attached):
##   [1] Rtsne_0.15                  colorspace_2.0-2           
##   [3] deldir_1.0-6                ellipsis_0.3.2             
##   [5] ggridges_0.5.3              XVector_0.34.0             
##   [7] GenomicRanges_1.46.1        spatstat.data_2.1-0        
##   [9] farver_2.1.0                leiden_0.3.9               
##  [11] listenv_0.8.0               ggrepel_0.9.1              
##  [13] fansi_0.5.0                 sparseMatrixStats_1.6.0    
##  [15] codetools_0.2-18            splines_4.1.3              
##  [17] knitr_1.36                  polyclip_1.10-0            
##  [19] jsonlite_1.7.2              ica_1.0-2                  
##  [21] cluster_2.1.3               png_0.1-7                  
##  [23] uwot_0.1.10                 shiny_1.7.1                
##  [25] sctransform_0.3.2           spatstat.sparse_2.0-0      
##  [27] compiler_4.1.3              httr_1.4.2                 
##  [29] assertthat_0.2.1            fastmap_1.1.0              
##  [31] lazyeval_0.2.2              later_1.3.0                
##  [33] htmltools_0.5.2             tools_4.1.3                
##  [35] igraph_1.2.11               GenomeInfoDbData_1.2.7     
##  [37] gtable_0.3.0                glue_1.5.1                 
##  [39] RANN_2.6.1                  reshape2_1.4.4             
##  [41] Rcpp_1.0.8                  Biobase_2.54.0             
##  [43] scattermore_0.7             jquerylib_0.1.4            
##  [45] vctrs_0.3.8                 nlme_3.1-153               
##  [47] DelayedMatrixStats_1.16.0   lmtest_0.9-39              
##  [49] xfun_0.28                   stringr_1.4.0              
##  [51] globals_0.14.0              mime_0.12                  
##  [53] miniUI_0.1.1.1              lifecycle_1.0.1            
##  [55] irlba_2.3.3                 goftest_1.2-3              
##  [57] future_1.23.0               zlibbioc_1.40.0            
##  [59] MASS_7.3-56                 zoo_1.8-9                  
##  [61] scales_1.1.1                spatstat.core_2.3-1        
##  [63] MatrixGenerics_1.6.0        promises_1.2.0.1           
##  [65] spatstat.utils_2.2-0        SummarizedExperiment_1.24.0
##  [67] parallel_4.1.3              yaml_2.2.1                 
##  [69] pbapply_1.5-0               gridExtra_2.3              
##  [71] sass_0.4.0                  rpart_4.1.16               
##  [73] stringi_1.7.6               highr_0.9                  
##  [75] S4Vectors_0.32.3            BiocGenerics_0.40.0        
##  [77] GenomeInfoDb_1.30.0         bitops_1.0-7               
##  [79] rlang_0.4.12                pkgconfig_2.0.3            
##  [81] matrixStats_0.61.0          glmGamPoi_1.6.0            
##  [83] evaluate_0.14               lattice_0.20-45            
##  [85] ROCR_1.0-11                 purrr_0.3.4                
##  [87] tensor_1.5                  labeling_0.4.2             
##  [89] patchwork_1.1.1             htmlwidgets_1.5.4          
##  [91] tidyselect_1.1.1            parallelly_1.29.0          
##  [93] RcppAnnoy_0.0.19            plyr_1.8.6                 
##  [95] magrittr_2.0.2              R6_2.5.1                   
##  [97] IRanges_2.28.0              generics_0.1.1             
##  [99] DelayedArray_0.20.0         DBI_1.1.1                  
## [101] pillar_1.6.4                withr_2.4.3                
## [103] mgcv_1.8-40                 fitdistrplus_1.1-6         
## [105] RCurl_1.98-1.5              survival_3.2-13            
## [107] abind_1.4-5                 tibble_3.1.6               
## [109] future.apply_1.8.1          crayon_1.4.2               
## [111] KernSmooth_2.23-20          utf8_1.2.2                 
## [113] spatstat.geom_2.3-0         plotly_4.10.0              
## [115] rmarkdown_2.11              grid_4.1.3                 
## [117] data.table_1.14.2           digest_0.6.29              
## [119] xtable_1.8-4                tidyr_1.1.4                
## [121] httpuv_1.6.3                stats4_4.1.3               
## [123] munsell_0.5.0               viridisLite_0.4.0          
## [125] bslib_0.3.1

  1. Institute of Psychiatry and Neuroscience of Paris, INSERM U1266, 75014, Paris, France, ↩︎

LS0tCnRpdGxlOiAiR21uYyBLTyBxdWFsaXR5IGNvbnRyb2wiCmF1dGhvcjoKICAgLSBNYXR0aGlldSBNb3JlYXVeW0luc3RpdHV0ZSBvZiBQc3ljaGlhdHJ5IGFuZCBOZXVyb3NjaWVuY2Ugb2YgUGFyaXMsIElOU0VSTSBVMTI2NiwgNzUwMTQsIFBhcmlzLCBGcmFuY2UsIG1hdHRoaWV1Lm1vcmVhdUBpbnNlcm0uZnJdIFshW10oaHR0cHM6Ly9vcmNpZC5vcmcvc2l0ZXMvZGVmYXVsdC9maWxlcy9pbWFnZXMvb3JjaWRfMTZ4MTYucG5nKV0oaHR0cHM6Ly9vcmNpZC5vcmcvMDAwMC0wMDAyLTI1OTItMjM3MykKZGF0ZTogImByIGZvcm1hdChTeXMudGltZSgpLCAnJWQgJUIsICVZJylgIgpvdXRwdXQ6IAogIGh0bWxfZG9jdW1lbnQ6IAogICAgY29kZV9kb3dubG9hZDogeWVzCiAgICBkZl9wcmludDogdGliYmxlCiAgICBoaWdobGlnaHQ6IGhhZGRvY2sKICAgIHRoZW1lOiBjb3NtbwogICAgY3NzOiAiLi4vc3R5bGUuY3NzIgogICAgdG9jOiB5ZXMKICAgIHRvY19kZXB0aDogNQogICAgdG9jX2Zsb2F0OgogICAgICBjb2xsYXBzZWQ6IHllcwotLS0KCmBgYHtyIHNldHVwLCBpbmNsdWRlPUZBTFNFfQprbml0cjo6b3B0c19jaHVuayRzZXQoZWNobyA9IFRSVUUsIGZpZy5hbGlnbiA9ICdjZW50ZXInLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFLCBjYWNoZS5sYXp5ID0gRkFMU0UpCmBgYAoKIyBMb2FkIGxpYnJhcmllcwoKYGBge3IgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0KbGlicmFyeShTZXVyYXQpCmxpYnJhcnkoTWF0cml4KQpsaWJyYXJ5KGRwbHlyKQpsaWJyYXJ5KFJDb2xvckJyZXdlcikKbGlicmFyeShnZ3Bsb3QyKQpsaWJyYXJ5KGdnRXh0cmEpCmxpYnJhcnkoY293cGxvdCkKbGlicmFyeShyZXRpY3VsYXRlKQpsaWJyYXJ5KHdlc2FuZGVyc29uKQp1c2VfcHl0aG9uKCIvdXNyL2Jpbi9weXRob24zIikKCiNTZXQgZ2dwbG90IHRoZW1lIGFzIGNsYXNzaWMKdGhlbWVfc2V0KHRoZW1lX2NsYXNzaWMoKSkKYGBgCgojIExvYWQgdGhlIHJhdyBjb3VudHMgbWF0cml4CgpgYGB7cn0KQ291bnRkYXRhIDwtIFJlYWQxMFgoIi4uLy4uL1Jhd0RhdGEvR21uY19LTy9vdXRzL2ZpbHRlcmVkX2ZlYXR1cmVfYmNfbWF0cml4LyIpCgpSYXcuZGF0YSA8LSBDcmVhdGVTZXVyYXRPYmplY3QoY291bnRzID0gQ291bnRkYXRhLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwcm9qZWN0ID0gIkdtbmNfS08iLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtaW4uY2VsbHMgPSAzLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtaW4uZmVhdHVyZXMgPSA4MDApCgpSYXcuZGF0YSRCYXJjb2RlcyA8LSByb3duYW1lcyhSYXcuZGF0YUBtZXRhLmRhdGEpCgpybShDb3VudGRhdGEpCgpkaW0oUmF3LmRhdGEpCmBgYApgYGB7cn0KUmF3LmRhdGEkcGVyY2VudC5taXRvIDwtIFBlcmNlbnRhZ2VGZWF0dXJlU2V0KFJhdy5kYXRhLCBwYXR0ZXJuID0gIl5tdC0iKQpSYXcuZGF0YSRwZXJjZW50LnJpYm8gPC0gUGVyY2VudGFnZUZlYXR1cmVTZXQoUmF3LmRhdGEsIHBhdHRlcm4gPSAiKF5ScGx8XlJwc3xeTXJwKSIpCmBgYAoKYGBge3J9ClZsblBsb3Qob2JqZWN0ID0gUmF3LmRhdGEsIGZlYXR1cmVzID0gYygibkZlYXR1cmVfUk5BIiwibkNvdW50X1JOQSIsICJwZXJjZW50Lm1pdG8iLCAicGVyY2VudC5yaWJvIiksIG5jb2w9IDIpICYgTm9BeGVzKCkKYGBgCiMgSW5zcGVjdCBjZWxsIGJhc2VkIG9uIHJlbGF0aW9uIGJldHdlZW4gblVNSSBhbmQgbkdlbmUgZGV0ZWN0ZWQKCmBgYHtyfQojIFJlbGF0aW9uIGJldHdlZW4gblVNSSBhbmQgbkdlbmUgZGV0ZWN0ZWQKQ2VsbC5RQy5TdGF0IDwtIFJhdy5kYXRhQG1ldGEuZGF0YQoKcDEgPC0gZ2dwbG90KENlbGwuUUMuU3RhdCwgYWVzKHg9bkNvdW50X1JOQSwgeT1uRmVhdHVyZV9STkEpKSArIGdlb21fcG9pbnQoKSArIGdlb21fc21vb3RoKG1ldGhvZD0ibG0iKQpwMSA8LSBnZ01hcmdpbmFsKHAxLCB0eXBlID0gImhpc3RvZ3JhbSIsIGZpbGw9ImxpZ2h0Z3JleSIpCgpwMiA8LSBnZ3Bsb3QoQ2VsbC5RQy5TdGF0LCBhZXMoeD1sb2cxMChuQ291bnRfUk5BKSwgeT1sb2cxMChuRmVhdHVyZV9STkEpKSkgKyBnZW9tX3BvaW50KCkgKyBnZW9tX3Ntb290aChtZXRob2Q9ImxtIikKcDIgPC0gZ2dNYXJnaW5hbChwMiwgdHlwZSA9ICJoaXN0b2dyYW0iLCBmaWxsPSJsaWdodGdyZXkiKQoKcGxvdF9ncmlkKHBsb3RsaXN0ID0gbGlzdChwMSxwMiksIG5jb2w9MiwgYWxpZ249J2gnLCByZWxfd2lkdGhzID0gYygxLCAxKSkgOyBybShwMSxwMikKYGBgCgpDZWxscyB3aXRoIGRldmlhdGluZyBuR2VuZS9uVU1JIHJhdGlvIGRpc3BsYXkgYW4gRXJ5dGhyb2N5dGUgc2lnbmF0dXJlIAoKCmBgYHtyfQpSYXcuZGF0YSA8LSBBZGRNb2R1bGVTY29yZShSYXcuZGF0YSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgZmVhdHVyZXMgPSBsaXN0KGMoIkhiYi1idCIsICJIYnExYSIsICJJc2cyMCIsICJGZWNoIiwgIlNuY2EiLCAiUmVjMTE0IikpLAogICAgICAgICAgICAgICAgICAgICAgICAgICBjdHJsID0gMTAsCiAgICAgICAgICAgICAgICAgICAgICAgICAgIG5hbWUgPSAiRXJ5dGhyb2N5dGUuc2lnbmF0dXJlIikKCkNlbGwuUUMuU3RhdCRFcnl0aHJvY3l0ZS5zaWduYXR1cmUgPC0gUmF3LmRhdGEkRXJ5dGhyb2N5dGUuc2lnbmF0dXJlMQpgYGAKCmBgYHtyfQpncmFkaWVudCA8LSBjb2xvclJhbXBQYWxldHRlKGJyZXdlci5wYWwobiA9MTEsIG5hbWUgPSAiU3BlY3RyYWwiKSkoMTAwKQoKcDEgPC0gZ2dwbG90KENlbGwuUUMuU3RhdCwgYWVzKGxvZzEwKG5Db3VudF9STkEpLCB5PWxvZzEwKG5GZWF0dXJlX1JOQSkpKSArCiAgICAgIGdlb21fcG9pbnQoYWVzKGNvbG9yPSBFcnl0aHJvY3l0ZS5zaWduYXR1cmUpKSAgKyAKICAgICAgc2NhbGVfY29sb3JfZ3JhZGllbnRuKGNvbG91cnM9cmV2KGdyYWRpZW50KSwgbmFtZT0nRXJ5dGhyb2N5dGUgc2NvcmUnKSArIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbj0ibm9uZSIpCgpwMiA8LSBnZ3Bsb3QoQ2VsbC5RQy5TdGF0LCBhZXMobG9nMTAobkNvdW50X1JOQSksIHk9bG9nMTAobkZlYXR1cmVfUk5BKSkpICsKICAgICAgZ2VvbV9wb2ludChhZXMoY29sb3I9IHBlcmNlbnQubWl0bykpICArIAogICAgICBzY2FsZV9jb2xvcl9ncmFkaWVudG4oY29sb3Vycz1yZXYoZ3JhZGllbnQpLCBuYW1lPSdQZXJjZW50IG1pdG8nKSArIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbj0ibm9uZSIpCgpwMyA8LSBnZ3Bsb3QoQ2VsbC5RQy5TdGF0LCBhZXMobG9nMTAobkNvdW50X1JOQSksIHk9bG9nMTAobkZlYXR1cmVfUk5BKSkpICsKICAgICAgZ2VvbV9wb2ludChhZXMoY29sb3I9IHBlcmNlbnQucmlibykpICArIAogICAgICBzY2FsZV9jb2xvcl9ncmFkaWVudG4oY29sb3Vycz1yZXYoZ3JhZGllbnQpLCBuYW1lPSdQZXJjZW50IHJpYm8nKSArIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbj0ibm9uZSIpCgpwMSArIHAyICsgcDMKYGBgCiMjIEV4Y2x1ZGUgRXJ5dGhyb2N5dGVzCgpgYGB7cn0KQ2VsbC5RQy5TdGF0JEVyeXRocm9jeXRlIDwtIGlmZWxzZShDZWxsLlFDLlN0YXQkRXJ5dGhyb2N5dGUuc2lnbmF0dXJlID4gMC4xLCAiRXJ5dGhyb2N5dGUiLCAiTm90X0VyeXRocm9jeXRlIikKYGBgCgpgYGB7cn0KcDIgPC0gZ2dwbG90KENlbGwuUUMuU3RhdCwgYWVzKHg9bG9nMTAobkNvdW50X1JOQSksIHk9bG9nMTAobkZlYXR1cmVfUk5BKSkpICsKICBnZW9tX3BvaW50KGFlcyhjb2xvdXIgPSBFcnl0aHJvY3l0ZSkpICsKICB0aGVtZShsZWdlbmQucG9zaXRpb249Im5vbmUiKQoKZ2dNYXJnaW5hbChwMiwgdHlwZSA9ICJoaXN0b2dyYW0iLCBmaWxsPSJsaWdodGdyZXkiKQpgYGAKCmBgYHtyfQojIEZpbHRlciBjZWxscyBiYXNlZCBvbiB0aGVzZSB0aHJlc2hvbGRzCkNlbGwuUUMuU3RhdCA8LSBDZWxsLlFDLlN0YXQgJT4lIGZpbHRlcihDZWxsLlFDLlN0YXQkRXJ5dGhyb2N5dGUuc2lnbmF0dXJlIDwgMC4xKQpgYGAKCiMgTG93IHF1YWxpdHkgY2VsbCBmaWx0ZXJpbmcKCiMjIEZpbHRlcmluZyBjZWxscyBiYXNlZCBvbiBwZXJjZW50YWdlIG9mIG1pdG9jaG9uZHJpYWwgdHJhbnNjcmlwdHMKCldlIGFwcGxpZWQgYSBoaWdoIGFuZCBsb3cgbWVkaWFuIGFic29sdXRlIGRldmlhdGlvbiAobWFkKSB0aHJlc2hvbGRzIHRvIGV4Y2x1ZGUgb3V0bGllciBjZWxscwoKYGBge3J9Cm1heC5taXRvLnRociA8LSBtZWRpYW4oQ2VsbC5RQy5TdGF0JHBlcmNlbnQubWl0bykgKyAzKm1hZChDZWxsLlFDLlN0YXQkcGVyY2VudC5taXRvKQptaW4ubWl0by50aHIgPC0gbWVkaWFuKENlbGwuUUMuU3RhdCRwZXJjZW50Lm1pdG8pIC0gMyptYWQoQ2VsbC5RQy5TdGF0JHBlcmNlbnQubWl0bykKYGBgCgpgYGB7cn0KcDEgPC0gZ2dwbG90KENlbGwuUUMuU3RhdCwgYWVzKHg9bkZlYXR1cmVfUk5BLCB5PXBlcmNlbnQubWl0bykpICsKICBnZW9tX3BvaW50KCkgKwogIGdlb21faGxpbmUoYWVzKHlpbnRlcmNlcHQgPSBtYXgubWl0by50aHIpLCBjb2xvdXIgPSAicmVkIiwgbGluZXR5cGUgPSAyKSArCiAgZ2VvbV9obGluZShhZXMoeWludGVyY2VwdCA9IG1pbi5taXRvLnRociksIGNvbG91ciA9ICJyZWQiLCBsaW5ldHlwZSA9IDIpICsKICBhbm5vdGF0ZShnZW9tID0gInRleHQiLCBsYWJlbCA9IHBhc3RlMChhcy5udW1lcmljKHRhYmxlKENlbGwuUUMuU3RhdCRwZXJjZW50Lm1pdG8gPiBtYXgubWl0by50aHIgfCBDZWxsLlFDLlN0YXQkcGVyY2VudC5taXRvIDwgbWluLm1pdG8udGhyKVsyXSksIiBjZWxscyByZW1vdmVkXG4iLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGFzLm51bWVyaWModGFibGUoQ2VsbC5RQy5TdGF0JHBlcmNlbnQubWl0byA+IG1heC5taXRvLnRociB8IENlbGwuUUMuU3RhdCRwZXJjZW50Lm1pdG8gPCBtaW4ubWl0by50aHIpWzFdKSwiIGNlbGxzIHJlbWFpbiIpLAogICAgICAgICAgIHggPSA2MDAwLCB5ID0gMjApCgpnZ01hcmdpbmFsKHAxLCB0eXBlID0gImhpc3RvZ3JhbSIsIGZpbGw9ImxpZ2h0Z3JleSIsIGJpbnM9MTAwKSAKYGBgCmBgYHtyfQojIEZpbHRlciBjZWxscyBiYXNlZCBvbiB0aGVzZSB0aHJlc2hvbGRzCkNlbGwuUUMuU3RhdCA8LSBDZWxsLlFDLlN0YXQgJT4lIGZpbHRlcihwZXJjZW50Lm1pdG8gPCBtYXgubWl0by50aHIpICU+JSBmaWx0ZXIocGVyY2VudC5taXRvID4gbWluLm1pdG8udGhyKQpgYGAKCiMjIEZpbHRlcmluZyBjZWxscyBiYXNlZCBvbiBudW1iZXIgb2YgZ2VuZXMgYW5kIHRyYW5zY3JpcHRzIGRldGVjdGVkCgojIyMgUmVtb3ZlIGNlbGxzIHdpdGggdG8gZmV3IGdlbmUgZGV0ZWN0ZWQgb3Igd2l0aCB0byBtYW55IFVNSSBjb3VudHMKCldlIGZpbHRlciBjZWxscyB3aGljaCBhcmUgbGlrZWx5IHRvIGJlIGRvdWJsZXQgYmFzZWQgb24gdGhlaXIgaGlnaGVyIGNvbnRlbnQgb2YgdHJhbnNjcmlwdCBkZXRlY3RlZCBhcyB3ZWxsIGFzIGNlbGwgd2l0aCB0byBmZXcgZ2VuZXMvVU1JIHNlcXVlbmNlZAoKYGBge3J9CiMgU2V0IGxvdyBhbmQgaGlnaHQgdGhyZXNob2xkcyBvbiB0aGUgbnVtYmVyIG9mIGRldGVjdGVkIGdlbmVzIGJhc2VkIG9uIHRoZSBvbmUgb2J0YWluIHdpdGggdGhlIFdUIGRhdGFzZXQKbWluLkdlbmVzLnRociA8LSBsb2cxMCgxNjM1KQptYXguR2VuZXMudGhyIDwtIGxvZzEwKDgwNjkpCgojIFNldCBoaWdodCB0aHJlc2hvbGQgb24gdGhlIG51bWJlciBvZiB0cmFuc2NyaXB0cwptYXgublVNSS50aHIgPC0gbG9nMTAoNTg5NTgpCmBgYAoKCmBgYHtyfQojIEdlbmUvVU1JIHNjYXR0ZXIgcGxvdCBiZWZvcmUgZmlsdGVyaW5nCnAxIDwtIGdncGxvdChDZWxsLlFDLlN0YXQsIGFlcyh4PWxvZzEwKG5Db3VudF9STkEpLCB5PWxvZzEwKG5GZWF0dXJlX1JOQSkpKSArCiAgZ2VvbV9wb2ludCgpICsKICBnZW9tX3Ntb290aChtZXRob2Q9ImxtIikgKwogIGdlb21faGxpbmUoYWVzKHlpbnRlcmNlcHQgPSBtaW4uR2VuZXMudGhyKSwgY29sb3VyID0gImdyZWVuIiwgbGluZXR5cGUgPSAyKSArCiAgZ2VvbV9obGluZShhZXMoeWludGVyY2VwdCA9IG1heC5HZW5lcy50aHIpLCBjb2xvdXIgPSAiZ3JlZW4iLCBsaW5ldHlwZSA9IDIpICsKICBnZW9tX3ZsaW5lKGFlcyh4aW50ZXJjZXB0ID0gbWF4Lm5VTUkudGhyKSwgY29sb3VyID0gInJlZCIsIGxpbmV0eXBlID0gMikKCmdnTWFyZ2luYWwocDEsIHR5cGUgPSAiaGlzdG9ncmFtIiwgZmlsbD0ibGlnaHRncmV5IikKYGBgCmBgYHtyfQojIEZpbHRlciBjZWxscyBiYXNlIG9uIGJvdGggbWV0cmljcwpDZWxsLlFDLlN0YXQgPC0gQ2VsbC5RQy5TdGF0ICU+JSBmaWx0ZXIobG9nMTAobkZlYXR1cmVfUk5BKSA+IG1pbi5HZW5lcy50aHIpICU+JSBmaWx0ZXIobG9nMTAobkNvdW50X1JOQSkgPCBtYXgublVNSS50aHIpCmBgYAoKIyMjIEZpbHRlciBjZWxscyBiZWxvdyB0aGUgbWFpbiBwb3B1bGF0aW9uIG5VTUkvbkdlbmUgcmVsYXRpb25zaGlwCgpgYGB7cn0KbG0ubW9kZWwgPC0gbG0oZGF0YSA9IENlbGwuUUMuU3RhdCwgZm9ybXVsYSA9IGxvZzEwKG5GZWF0dXJlX1JOQSkgfiBsb2cxMChuQ291bnRfUk5BKSkKCnAyIDwtIGdncGxvdChDZWxsLlFDLlN0YXQsIGFlcyh4PWxvZzEwKG5Db3VudF9STkEpLCB5PWxvZzEwKG5GZWF0dXJlX1JOQSkpKSArCiAgZ2VvbV9wb2ludCgpICsKICBnZW9tX3Ntb290aChtZXRob2Q9ImxtIikgKwogIGdlb21faGxpbmUoYWVzKHlpbnRlcmNlcHQgPSBtaW4uR2VuZXMudGhyKSwgY29sb3VyID0gImdyZWVuIiwgbGluZXR5cGUgPSAyKSArCiAgZ2VvbV9obGluZShhZXMoeWludGVyY2VwdCA9IG1heC5HZW5lcy50aHIpLCBjb2xvdXIgPSAiZ3JlZW4iLCBsaW5ldHlwZSA9IDIpICsKICBnZW9tX3ZsaW5lKGFlcyh4aW50ZXJjZXB0ID0gbWF4Lm5VTUkudGhyKSwgY29sb3VyID0gInJlZCIsIGxpbmV0eXBlID0gMikgKwogIGFubm90YXRlKGdlb20gPSAidGV4dCIsIGxhYmVsID0gcGFzdGUwKGRpbShDZWxsLlFDLlN0YXQpWzFdLCAiIFFDIHBhc3NlZCBjZWxscyIpLCB4ID0gNCwgeSA9IDMuOCkKCmdnTWFyZ2luYWwocDIsIHR5cGUgPSAiaGlzdG9ncmFtIiwgZmlsbD0ibGlnaHRncmV5IikKYGBgCiMjIEZpbHRlciB0aGUgU2V1cmF0IG9iamVjdAoKYGBge3J9ClJhdy5kYXRhIDwtIHN1YnNldCh4ID0gUmF3LmRhdGEsIHN1YnNldCA9IEJhcmNvZGVzICVpbiUgIENlbGwuUUMuU3RhdCRCYXJjb2RlcykKYGBgCgpgYGB7cn0KIyBQbG90IGZpbmFsIFFDIG1ldHJpY3MKVmxuUGxvdChvYmplY3QgPSBSYXcuZGF0YSwgZmVhdHVyZXMgPSBjKCJuRmVhdHVyZV9STkEiLCJuQ291bnRfUk5BIiwgInBlcmNlbnQubWl0byIsICJwZXJjZW50LnJpYm8iKSwgbmNvbD0gMikgJiBOb0F4ZXMoKQpgYGAKYGBge3J9CnAxIDwtIGdncGxvdChSYXcuZGF0YUBtZXRhLmRhdGEsIGFlcyh4PWxvZzEwKG5Db3VudF9STkEpLCB5PWxvZzEwKG5GZWF0dXJlX1JOQSkpKSArIGdlb21fcG9pbnQoKSArIGdlb21fc21vb3RoKG1ldGhvZD0ibG0iKQpnZ01hcmdpbmFsKHAxLCB0eXBlID0gImhpc3RvZ3JhbSIsIGZpbGw9ImxpZ2h0Z3JleSIpCmBgYApgYGB7cn0Kcm0obGlzdCA9IGxzKClbIWxzKCkgJWluJSAiUmF3LmRhdGEiXSkKYGBgCgoKIyBVc2UgU2NydWJsZXQgdG8gZGV0ZWN0IG9idmlvdXMgZG91YmxldHMKCiMjIFJ1biBTY3J1YmxldCB3aXRoIGRlZmF1bHQgcGFyYW1ldGVyCgpFeHBvcnQgcmF3IGNvdW50IG1hdHJpeCBhcyBpbnB1dCB0byBTY3J1YmxldAoKYGBge3J9CiNFeHBvcnQgZmlsdGVyZWQgbWF0cml4CmRpci5jcmVhdGUoIi4uLy4uL1Jhd0RhdGEvR21uY19LTy9TY3J1YmxldF9pbnB1dHMiKQoKZXhwckRhdGEgPC0gTWF0cml4KGFzLm1hdHJpeChSYXcuZGF0YUBhc3NheXNbWyJSTkEiXV1AY291bnRzKSwgc3BhcnNlID0gVFJVRSkKd3JpdGVNTShleHByRGF0YSwgIi4uLy4uL1Jhd0RhdGEvR21uY19LTy9TY3J1YmxldF9pbnB1dHMvbWF0cml4MS5tdHgiKQpgYGAKYGBge3B5dGhvbn0KaW1wb3J0IHNjcnVibGV0IGFzIHNjcgppbXBvcnQgc2NpcHkuaW8KaW1wb3J0IG51bXB5IGFzIG5wCmltcG9ydCBvcwoKI0xvYWQgcmF3IGNvdW50cyBtYXRyaXggYW5kIGdlbmUgbGlzdAppbnB1dF9kaXIgPSAnLi4vLi4vUmF3RGF0YS9HbW5jX0tPL1NjcnVibGV0X2lucHV0cycKY291bnRzX21hdHJpeCA9IHNjaXB5LmlvLm1tcmVhZChpbnB1dF9kaXIgKyAnL21hdHJpeDEubXR4JykuVC50b2NzYygpCgojSW5pdGlhbGl6ZSBTY3J1YmxldApzY3J1YiA9IHNjci5TY3J1YmxldChjb3VudHNfbWF0cml4LAogICAgICAgICAgICAgICAgICAgICBleHBlY3RlZF9kb3VibGV0X3JhdGU9MC4xLAogICAgICAgICAgICAgICAgICAgICBzaW1fZG91YmxldF9yYXRpbz0yLAogICAgICAgICAgICAgICAgICAgICBuX25laWdoYm9ycyA9IDgpCgojUnVuIHRoZSBkZWZhdWx0IHBpcGVsaW5lCmRvdWJsZXRfc2NvcmVzLCBwcmVkaWN0ZWRfZG91YmxldHMgPSBzY3J1Yi5zY3J1Yl9kb3VibGV0cyhtaW5fY291bnRzPTEsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbWluX2NlbGxzPTMsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbWluX2dlbmVfdmFyaWFiaWxpdHlfcGN0bD04NSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBuX3ByaW5fY29tcHM9MjUpCmBgYAoKYGBge3J9CiMgSW1wb3J0IHNjcnVibGV0J3MgZG91YmxldCBzY29yZQpSYXcuZGF0YSREb3VibGV0c2NvcmUgPC0gcHkkZG91YmxldF9zY29yZXMKCiMgUGxvdCBkb3VibGV0IHNjb3JlCmdncGxvdChSYXcuZGF0YUBtZXRhLmRhdGEsIGFlcyh4ID0gRG91YmxldHNjb3JlLCBzdGF0KG5kZW5zaXR5KSkpICsKICBnZW9tX2hpc3RvZ3JhbShiaW5zID0gMjAwLCBjb2xvdXIgPSJsaWdodGdyZXkiKSsKICBnZW9tX3ZsaW5lKHhpbnRlcmNlcHQgPSAwLjE1LCBjb2xvdXIgPSAicmVkIiwgbGluZXR5cGUgPSAyKQpgYGAKYGBge3J9CiMgTWFudWFsbHkgc2V0IHRocmVzaG9sZCBhdCBkb3VibGV0IHNjb3JlIHRvIDAuMgpSYXcuZGF0YSRQcmVkaWN0ZWRfZG91YmxldHMgPC0gaWZlbHNlKHB5JGRvdWJsZXRfc2NvcmVzID4gMC4xNSwgIkRvdWJsZXQiLCJTaW5nbGV0IikKdGFibGUoUmF3LmRhdGEkUHJlZGljdGVkX2RvdWJsZXRzKQpgYGAKYGBge3J9ClJhdy5kYXRhIDwtIHN1YnNldCh4ID0gUmF3LmRhdGEsIHN1YnNldCA9IFByZWRpY3RlZF9kb3VibGV0cyA9PSAiU2luZ2xldCIpCmBgYAoKIyBHZW5lcmF0ZSBTUklORyBkaW1lbnRpb25hbGl0eSByZWR1Y3Rpb24KCiMjIEV4cG9ydCBjb3VudHMgbWF0cml4CgpgYGB7cn0KZGlyLmNyZWF0ZSgiLi9TcHJpbmdDb29yZGluYXRlcyIpCmBgYAoKYGBge3J9CiMgRXhwb3J0IHJhdyBleHByZXNzaW9uIG1hdHJpeCBhbmQgZ2VuZSBsaXN0IHRvIHJlZ2VuZXJhdGUgYSBzcHJpbmcgcGxvdApleHByRGF0YSA8LSBNYXRyaXgoYXMubWF0cml4KFJhdy5kYXRhQGFzc2F5c1tbIlJOQSJdXUBjb3VudHMpLCBzcGFyc2UgPSBUUlVFKQp3cml0ZU1NKGV4cHJEYXRhLCAiLi9TcHJpbmdDb29yZGluYXRlcy9FeHByRGF0YS5tdHgiKQpgYGAKCmBgYHtyfQpHZW5lbGlzdCA8LSByb3cubmFtZXMoUmF3LmRhdGFAYXNzYXlzW1siUk5BIl1dQGNvdW50cykKd3JpdGUudGFibGUoR2VuZWxpc3QsICIuL1NwcmluZ0Nvb3JkaW5hdGVzL0dlbmVsaXN0LmNzdiIsIHNlcD0iXHQiLCBjb2wubmFtZXMgPSBGLCByb3cubmFtZXMgPSBGLCBxdW90ZSA9IEYpCmBgYAoKYGBge3J9CiNFeHBvcnQgbWV0YWRhdGEKU2NydWJsZXQgPC0gYygiU2NydWJsZXQiLCBSYXcuZGF0YSRQcmVkaWN0ZWRfZG91YmxldHMpClNjcnVibGV0IDwtIHBhc3RlKFNjcnVibGV0LCBzZXA9IiwiLCBjb2xsYXBzZT0iLCIpCgpDZWxsZ3JvdXBpbmcgPC0gU2NydWJsZXQKd3JpdGUudGFibGUoQ2VsbGdyb3VwaW5nLCAiLi9TcHJpbmdDb29yZGluYXRlcy9DZWxsZ3JvdXBpbmcuY3N2IiwgcXVvdGUgPUYsIHJvdy5uYW1lcyA9IEYsIGNvbC5uYW1lcyA9IEYpCmBgYAoKIyMgSW1wb3J0IGNvb3JkaW5hdGVzCgpgYGB7cn0Kc3ByaW5nLmNvb3IgPC0gcmVhZC50YWJsZSgiU3ByaW5nQ29vcmRpbmF0ZXMvY29vcmRpbmF0ZXMudHh0Iiwgc2VwID0gIiwiLCBoZWFkZXIgPSBGLCByb3cubmFtZXMgPSAxKQpjb2xuYW1lcyhzcHJpbmcuY29vcikgPC0gYygiU3ByaW5nXzEiLCAiU3ByaW5nXzIiKQpgYGAKCmBgYHtyfQpTcHJpbmcuU3ltIDwtIGZ1bmN0aW9uKHgpewogIHggPSBhYnMobWF4KHNwcmluZy5jb29yJFNwcmluZ18yKS14KQogfQoKc3ByaW5nLmNvb3IkU3ByaW5nXzIgPC0gc2FwcGx5KHNwcmluZy5jb29yJFNwcmluZ18yLCBmdW5jdGlvbih4KSBTcHJpbmcuU3ltKHgpKQpgYGAKCmBgYHtyfQpSYXcuZGF0YSRTcHJpbmdfMSA8LSBzcHJpbmcuY29vciRTcHJpbmdfMQpSYXcuZGF0YSRTcHJpbmdfMiA8LSBzcHJpbmcuY29vciRTcHJpbmdfMgpgYGAKCgpgYGB7cn0Kc3ByaW5nIDwtIGFzLm1hdHJpeChSYXcuZGF0YUBtZXRhLmRhdGEgJT4lIHNlbGVjdCgiU3ByaW5nXzEiLCAiU3ByaW5nXzIiKSkKICAKUmF3LmRhdGFbWyJzcHJpbmciXV0gPC0gQ3JlYXRlRGltUmVkdWNPYmplY3QoZW1iZWRkaW5ncyA9IHNwcmluZywga2V5ID0gIlNwcmluZ18iLCBhc3NheSA9IERlZmF1bHRBc3NheShSYXcuZGF0YSkpCmBgYAoKYGBge3J9CkRpbVBsb3QoUmF3LmRhdGEsIAogICAgICAgIHJlZHVjdGlvbiA9ICJzcHJpbmciLAogICAgICAgIHB0LnNpemUgPSAwLjUpICYgTm9BeGVzKCkKYGBgCiMgU2N0cmFuc2Zvcm0gbm9ybWFsaXphdGlvbgoKYGBge3IgY2xhc3Mub3V0cHV0PSJzY3JvbGwtMTAwIn0KUmF3LmRhdGEgPC0gU0NUcmFuc2Zvcm0oUmF3LmRhdGEsCiAgICAgICAgICAgICAgICAgICAgICAgIG1ldGhvZCA9ICJnbG1HYW1Qb2kiLAogICAgICAgICAgICAgICAgICAgICAgICB2YXJzLnRvLnJlZ3Jlc3MgPSBjKCJwZXJjZW50Lm1pdG8iKSwKICAgICAgICAgICAgICAgICAgICAgICAgdmVyYm9zZSA9IFQpCmBgYAojIFJ1biBQQ0EgYW5kIGJyb2FkIGNsdXN0ZXJpbmcKCmBgYHtyIGNsYXNzLm91dHB1dD0ic2Nyb2xsLTEwMCJ9ClJhdy5kYXRhIDwtIFJ1blBDQShSYXcuZGF0YSwgdmVyYm9zZSA9IEZBTFNFKQoKUmF3LmRhdGEgPC0gRmluZE5laWdoYm9ycyhSYXcuZGF0YSwKICAgICAgICAgICAgICAgICAgICAgICAgICBkaW1zID0gMToyMCwKICAgICAgICAgICAgICAgICAgICAgICAgICBrLnBhcmFtID0gOCkKClJhdy5kYXRhIDwtIEZpbmRDbHVzdGVycyhSYXcuZGF0YSwgcmVzb2x1dGlvbiA9IDAuMSkKYGBgCgpgYGB7cn0KRGltUGxvdChSYXcuZGF0YSwKICAgICAgICByZWR1Y3Rpb24gPSAic3ByaW5nIiwKICAgICAgICBjb2xzID0gYyh3ZXNfcGFsZXR0ZSgiRmFudGFzdGljRm94MSIpLCIjOWVjMjJmIiwiZ3JleTYwIiksCiAgICAgICAgcHQuc2l6ZSA9IDAuNSkgJiBOb0F4ZXMoKQpgYGAKCiMgUGxvdCBtYXJrZXIgZ2VuZXMgZm91bmQgaW4gdGhlIFdUIGRhdGFzZXQKCmBgYHtyfQpGZWF0dXJlUGxvdChvYmplY3QgPSBSYXcuZGF0YSwKICAgICAgICAgICAgZmVhdHVyZXMgPSBjKCJUYnIxIiwiRm94ZzEiLCAiVHJwNzMiLCAiSHRyMmMiLAogICAgICAgICAgICAgICAgICAgICAgICAgIlNoaXNhMiIsICJXaWYxIiwgIlJhc3NmNCIsIkRrazMiLAogICAgICAgICAgICAgICAgICAgICAgICAgIkRsazEiLCAiU3VsZjEiLCAiVHRyIiwgIkZveGMxIiwgIkMxcWIiKSwKICAgICAgICAgICAgcHQuc2l6ZSA9IDAuMiwKICAgICAgICAgICAgY29scyA9IGMoImdyZXk5MCIsIGJyZXdlci5wYWwoOSwiWWxHbkJ1IikpLAogICAgICAgICAgICByZWR1Y3Rpb24gPSAic3ByaW5nIiwKICAgICAgICAgICAgb3JkZXIgPSBUKSAmIE5vQXhlcygpICYgTm9MZWdlbmQoKQpgYGAKCgojIFNhdmUgdGhlIG9iamVjdAoKYGBge3IgU2F2ZSBSRFN9CnNhdmVSRFMoUmF3LmRhdGEsICIuL0dtbmNLTy5jZWxscy5SRFMiKQpgYGAKCgojIFNlc3Npb24gSW5mbwoKYGBge3J9CiNkYXRlCmZvcm1hdChTeXMudGltZSgpLCAiJWQgJUIsICVZLCAlSCwlTSIpCgojUGFja2FnZXMgdXNlZApzZXNzaW9uSW5mbygpCmBgYA==